package com.atguigu.gmall.activity.consumer;

import com.atguigu.gmall.activity.mapper.SeckillGoodsMapper;
import com.atguigu.gmall.activity.redis.CacheHelper;
import com.atguigu.gmall.activity.util.DateUtil;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import com.atguigu.gmall.model.activity.SeckillGoods;
import com.atguigu.gmall.model.activity.UserRecode;
import com.atguigu.gmall.rabbit.constant.MqConst;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * @Author: 李旭
 * @Time: 15:41
 * @Description: 接收秒杀相关活动信息
 */
@Component
public class ActivityConsumer {


    @Autowired
    private SeckillGoodsMapper seckillGoodsMapper;
    @Autowired
    private RedisTemplate redisTemplate;

    //半夜12点接收消息
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_TASK_1, durable = "true", autoDelete = "false"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_TASK),
            key = MqConst.ROUTING_TASK_1
    ))
    public void seckillImportRedis(Message message, Channel channel) {
        try {
            //将秒杀表的数据导入缓存  当天的

/*            select * from seckill_goods
            where status = 1 and stock_count > 0
            and DATE_FORMAT(start_time,'%Y-%m-%d') = '2021-04-27'*/

            //4:查询
            QueryWrapper<SeckillGoods> queryWrapper = new QueryWrapper();
            //1:审核通过
            queryWrapper.eq("status", 1);
            //3:必须有剩余库存的商品
            queryWrapper.gt("stock_count", 0);
            //2:当天的商品
            queryWrapper.eq("DATE_FORMAT(start_time,'%Y-%m-%d')",
                    DateUtil.formatDate(new Date()));
            //Date time = Calendar.getInstance().getTime();
            List<SeckillGoods> seckillGoodsList = seckillGoodsMapper.selectList(queryWrapper);
            if (!CollectionUtils.isEmpty(seckillGoodsList)) {
                //今天有秒杀的商品

                seckillGoodsList.forEach(seckillGoods -> {
                    //5:将结果集保存到Redis缓存中  （考虑 使用redis五大数据类型中哪个类型）
                    //Hash类型    h   hk hv
                    //5.1判断缓存是否已经存在
                    if (!redisTemplate.opsForHash().hasKey(RedisConst.SECKILL_GOODS,
                            seckillGoods.getSkuId().toString())) {
                        //作为新秒杀商品保存到缓存中
                        redisTemplate.opsForHash().put(RedisConst.SECKILL_GOODS,
                                seckillGoods.getSkuId().toString(), seckillGoods);
                        //6:防止超卖   秒杀商品放到货架
                        // K : List 超市名称:苹果 = new ArrayList
                        // k.add(苹果)
                        // k.add(苹果)
                        // k.add(苹果)
                        //超市名称:苹果.get(苹果)
                        // K : List 超市名称:梨 = new ArrayList
                        // k.add(梨)
                        // k.add(梨)
                        redisTemplate.opsForList().leftPushAll(RedisConst.SECKILL_STOCK_PREFIX
                                        + seckillGoods.getSkuId(),
                                buildSkuIds(seckillGoods.getSkuId(), seckillGoods.getStockCount()));
                        //7:状态位   每一款商品都要有状态位
                        //参数1：信道
                        //参数2：消息   skuId:0  skuId:1
                        redisTemplate.convertAndSend("seckillpush",
                                seckillGoods.getSkuId() + ":1");

                    }

                });
            }

            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_SECKILL_USER, durable = "true", autoDelete = "false"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_SECKILL_USER),
            key = MqConst.ROUTING_SECKILL_USER
    ))
    public void seckill(UserRecode userRecode, Message message, Channel channel) {
        try {
//            1、校验状态位
            Object status = CacheHelper.get(userRecode.getSkuId().toString());
            if (!"1".equals(status)) {
                return;
            }
//            2、用户是否来过   setnx   set之前判断是否已经存在  如果存在了返回0 如果不存在返回1 true
            Boolean flag = redisTemplate.opsForValue().setIfAbsent(
                    RedisConst.SECKILL_USER + userRecode.getUserId(), "1");
            if (!flag) {
                //来过
                return;
            }
//            3、redis leftpop
            String skuId = (String) redisTemplate.opsForList().rightPop(RedisConst.SECKILL_STOCK_PREFIX
                    + userRecode.getSkuId());
            if(null == skuId){
//            4、没有  修改状态位
                redisTemplate.convertAndSend("seckillpush",
                        userRecode.getSkuId() + ":0");
                return;
            }
//            5、有 将资格保存在Redis
            redisTemplate.opsForValue().set(
                    RedisConst.SECKILL_ORDERS + userRecode.getUserId(),userRecode.getSkuId());
//            6、收尾!更新一下库存
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }


    //数组 String[] ids = {skuId,skuId,skuId}
    public String[] buildSkuIds(Long skuId, Integer stock) {
        String[] ids = new String[stock];
        for (Integer i = 0; i < stock; i++) {
            ids[i] = skuId.toString();
        }
        return ids;
    }

}
